package com.jxpanda.infrastructure.core.tollkit.json;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;
import com.jxpanda.infrastructure.core.tollkit.ReflectionKit;
import com.jxpanda.infrastructure.core.tollkit.StringKit;
import lombok.SneakyThrows;

import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;

/**
 * Json序列化/反序列化工具
 * <p>
 * 【可选功能】调用 registerImageModule(String domain) 函数，增加处理图片相对路径 --> 绝对路径的功能
 * -- 此功能只做序列化的转换，反序列化不处理，功能一旦启用就无法关闭（暂时没有提供关闭功能）
 * -- 重新调用 registerImageModule(String domain) 函数 传入新的域名可以替换域名
 * -- 调用 addImageField(String field) 增加被代理的图片字段，remove同理
 * -- 默认代理的字段有
 * "image", "images", "imageList",
 * "img", "imgList",
 * "picture", "pictures", "pictureList",
 * "pic", "pics", "picList"
 *
 * @author Panda
 */
public class JsonKit {


    /**
     * 返回字符串是否是一个json
     * 原理是利用Jackson的ObjectMapper尝试解析一次，不报错就是Json
     *
     */
    public static boolean isJson(String string) {
        if (StringKit.isBlank(string)) {
            return false;
        }
        try {
            fromJson(string);
        } catch (Exception ex) {
            return false;
        }
        return true;
    }

    /**
     * 把对象转为json字符串
     */
    @SneakyThrows
    public static String toJson(Object object) {
        return jackson().writeValueAsString(object);
    }

    /**
     * 把对象转为json字符串
     */
    @SneakyThrows
    public static Map<String, Object> toMap(Object object) {
        if (object instanceof Map) {
            return ReflectionKit.cast(object);
        }
        // 做两次转换，转为map
        return fromJson(toJson(object));
    }


    /**
     * 把json字符串转为Map
     */
    @SneakyThrows
    public static Map<String, Object> fromJson(String json) {
        return fromJson(json, new TypeReference<>() {
        });
    }


    /**
     * 把json字符串转为对象
     */
    @SneakyThrows
    public static <T> T fromJson(byte[] jsonBytes, Class<T> clazz) {
        return jackson().readValue(jsonBytes, clazz);
    }


    /**
     * 把json字符串转为对象
     * 取值跟着泛型走，这个可以传递List进来
     */
    @SneakyThrows
    public static <T> T fromJson(byte[] jsonBytes, TypeReference<T> typeReference) {
        return jackson().readValue(jsonBytes, typeReference);
    }


    /**
     * 把json字符串转为对象
     */
    @SneakyThrows
    public static <T> T fromJson(String json, Class<T> clazz) {
        return jackson().readValue(json, clazz);
    }

    /**
     * 把json字符串转为对象
     * 取值跟着泛型走，这个可以传递List进来
     */
    @SneakyThrows
    public static <T> T fromJson(String json, TypeReference<T> typeReference) {
        return jackson().readValue(json, typeReference);
    }

    public static JsonRepair repairMode(String json) {
        return new JsonRepair(json);
    }

    /**
     * 懒加载单例模式
     */
    public static ObjectMapper jackson() {
        return JacksonHolder.getInstance();
    }


    public static void init(ObjectMapper customMapper) {
        JacksonHolder.init(customMapper);
    }


    private static class JacksonHolder {
        // 原子引用，初始为 null
        private static final AtomicReference<ObjectMapper> INSTANCE = new AtomicReference<>();

        /**
         * 显式注入一个自定义的 ObjectMapper。
         * 只有当 INSTANCE 还是 null 时才能成功初始化，
         * 否则抛出异常，永不被覆盖。
         */
        private static void init(ObjectMapper customMapper) {
            Objects.requireNonNull(customMapper, "The customMapper can not be null");
            boolean ok = INSTANCE.compareAndSet(null, customMapper);
            if (!ok) {
                throw new IllegalStateException("The ObjectMapper has already been initialized and cannot be initialized again");
            }
        }

        private static ObjectMapper getInstance() {
            return JacksonHolder.INSTANCE.updateAndGet(existing -> existing != null ? existing : JacksonBuilder.defaultMapper());
        }

    }

}
